﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Qetza.TeamFoundation.WorkItemQuery.Admin
{
    /// <summary>
    /// Represents a standard parameter validator.
    /// </summary>
    public class ParameterValidator : IParameterValidator
    {
        #region IParameterValidator Members

        /// <inheritdoc />
        public void Validate(
            IDictionary<string, string> specifiedParameters, 
            IEnumerable<ParameterInfo> allowedParameters,
            Action<IDictionary<string, string>> customValidation
            )
        {
            // unexpected switch
            var parameterInfos = allowedParameters.ToDictionary(pi => pi.Name);

            foreach (var param in specifiedParameters)
            {
                if (!parameterInfos.ContainsKey(param.Key))
                {
                    throw new InvalidParameterException(
                        string.Format(ResourceStrings.InvalidParam, param.Key),
                        param.Key
                        );
                }
            }

            foreach (var paramInfo in parameterInfos.Values)
            {
                // missing required switch
                if (paramInfo.IsRequired && !specifiedParameters.ContainsKey(paramInfo.Name))
                {
                    throw new InvalidParameterException(
                        string.Format(ResourceStrings.MissingSwitch, paramInfo.Name),
                        paramInfo.Name
                        );
                }

                // flag with value
                if (paramInfo.IsFlag &&
                    specifiedParameters.ContainsKey(paramInfo.Name) &&
                    !string.IsNullOrEmpty(specifiedParameters[paramInfo.Name])
                    )
                {
                    throw new InvalidParameterException(
                        string.Format(ResourceStrings.SwitchHasValue, paramInfo.Name),
                        paramInfo.Name
                        );
                }

                // non flag without value
                if (!paramInfo.IsFlag &&
                    specifiedParameters.ContainsKey(paramInfo.Name) &&
                    string.IsNullOrEmpty(specifiedParameters[paramInfo.Name])
                    )
                {
                    throw new InvalidParameterException(
                        string.Format(ResourceStrings.SwitchRequiresValue, paramInfo.Name),
                        paramInfo.Name
                        );
                }

                // incompatible arguments
                if (paramInfo.IncompatibleArguments != null && specifiedParameters.ContainsKey(paramInfo.Name))
                {
                    var incompatiableArgument = specifiedParameters.FirstOrDefault(p => paramInfo.IncompatibleArguments.Contains(p.Key)).Key;
                    if (incompatiableArgument != null)
                    {
                        throw new InvalidParameterException(
                            string.Format(ResourceStrings.IncompatibleSwitch, paramInfo.Name, incompatiableArgument),
                            paramInfo.Name
                            );
                    }
                }

                // allowed values
                if (paramInfo.AllowedValues != null && 
                    specifiedParameters.ContainsKey(paramInfo.Name) && 
                    !paramInfo.AllowedValues.Contains(specifiedParameters[paramInfo.Name]))
                {
                    throw new InvalidParameterException(
                        string.Format(ResourceStrings.NotAllowedParamValue, specifiedParameters[paramInfo.Name], paramInfo.Name),
                        paramInfo.Name
                        );
                }
            }

            // custom command validation
            if (customValidation != null)
            {
                customValidation(specifiedParameters);
            }
        }

        /// <inheritdoc />
        public string GetSyntax(IEnumerable<ParameterInfo> parameters)
        {
            var sb = new StringBuilder();
            foreach (var param in parameters)
            {
                if (!param.IsRequired)
                {
                    sb.Append("[");
                }

                sb.Append(param.Name);

                if (!param.IsFlag)
                {
                    sb.Append(":");
                    sb.Append(param.ArgumentName);
                }

                if (!param.IsRequired)
                {
                    sb.Append("]");
                }

                sb.Append(" ");
            }

            return sb.ToString();
        }

        #endregion
    }
}
